#include "Debug.h"
#include "AngleSpace.h"

AngleSpace::AngleSpace(MItMeshEdge* edgeIt, MItMeshPolygon* faceIt, MItMeshVertex* vertsIt, vector<int> seamVerts, vector<int> seamEdges)
{
	faceIt->reset();
	vertsIt->reset();
	edgeIt->reset();

	while(!vertsIt->isDone())
	{
		int index = vertsIt->index();		
		VertexBase* newCorner = new VertexBase(index, vertsIt->position());
		if(vertsIt->onBoundary())
			newCorner->setBoundary(true);		
		if(find(seamVerts.begin(), seamVerts.end(), index) != seamVerts.end() && !vertsIt->onBoundary())
			newCorner->setBoundary(true);		
		vertices[index] = newCorner;
		vertsIt->next();
	}
	while(!edgeIt->isDone())
	{
		int index = edgeIt->index();
		bool boundary = false;
		if(edgeIt->onBoundary() || find(seamEdges.begin(), seamEdges.end(), index) != seamEdges.end() )
			boundary = true;

		EdgeBase* newEdge = new EdgeBase(index, vertices[edgeIt->index(0)], vertices[edgeIt->index(1)], boundary);
		edges[index] = newEdge;
		edgeIt->next();
	}	
	while(!faceIt->isDone())
	{	
		MIntArray verticesIndices;
		faceIt->getVertices(verticesIndices);
		MIntArray edgeIndices;
		faceIt->getEdges(edgeIndices);
	
		VertexBase* aCorner = vertices[verticesIndices[0]];
		VertexBase* bCorner = vertices[verticesIndices[1]];
		VertexBase* cCorner = vertices[verticesIndices[2]];

		EdgeBase* abEdge = edges[edgeIndices[0]];
		EdgeBase* bcEdge = edges[edgeIndices[1]];
		EdgeBase* caEdge = edges[edgeIndices[2]];

		TriangleBase* tri = new TriangleBase(faceIt, vertsIt, faceIt->index(), aCorner, bCorner, cCorner, abEdge, bcEdge, caEdge);

		abEdge->addTriangle(tri, cCorner);
		bcEdge->addTriangle(tri, aCorner);
		caEdge->addTriangle(tri, bCorner);

		triangles[faceIt->index()] = tri;
		faceIt->next();
	}

	for(int j=0; j<triangles.size(); j++)		
		triangles[j]->setOptimalAngles();	

	//printAngleSpace();
}

void AngleSpace::updateAngles(const vector<double> newAngles)
{
	if(newAngles.size() % 3 != 0)
		cout << "Error: Angle update is not divisiable by three" << endl;

	//cout << "New Angles" << endl;
	//for(int i=0; i<newAngles.size(); i++)
	//	cout << "\t" << newAngles[i] << endl;

	int i=0;
	for(int j=0; j<triangles.size(); j++)	
	{
		TriangleBase::angleTriple triple;
		triple.A = newAngles[i++];
		triple.B = newAngles[i++];
		triple.C = newAngles[i++];
		triangles[j]->updateAngles(triple);	
	}
}

vector<double>* AngleSpace::getAngles()
{
	vector<double>* allAngles = new vector<double>;

	for(int j=0; j<triangles.size(); j++)	
	{
		TriangleBase::angleTriple triple = triangles[j]->getAngles();
		allAngles->push_back(triple.A);
		allAngles->push_back(triple.B);
		allAngles->push_back(triple.C);
	}
	if(allAngles->size() % 3 != 0)
		cout << "Error: Angle Grab is not divisiable by three" << endl;

	return allAngles;
}

double AngleSpace::angularDistortion()
{
	double angularDistortion =0;
	for(int i=0; i<triangles.size(); i++)	
		angularDistortion += triangles[i]->getAngularDistortion();	
	return angularDistortion;
}

double AngleSpace::triangleValidity()
{
	double validity =0;
	for(int i=0; i<triangles.size(); i++)
		validity += abs(triangles[i]->sumAngles() - 180);
	return validity;
}

double AngleSpace::planarValidity()
{
	double planarity = 0;
	for(int i=0; i<vertices.size(); i++)
		if(!vertices[i]->onBoundary())
			planarity += abs(vertices[i]->sumAngles() - 360);
	return planarity;
}

double AngleSpace::wheelValidity()
{
	double reconstruction = 0;
	for(int i=0; i<vertices.size(); i++)
		if(!vertices[i]->onBoundary())
			reconstruction += vertices[i]->reconstructability();
	return reconstruction;
}

AngleSpace::~AngleSpace(void)
{
	for (map<int, TriangleBase*>::iterator it=triangles.begin(); it!=triangles.end(); ++it)		
		delete it->second;
	for (map<int, VertexBase*>::iterator it=vertices.begin(); it!=vertices.end(); ++it)	
		delete it->second;	
}

VertexBase* AngleSpace::getCorner(int i)
{
	return vertices[i];
}

void AngleSpace::printAngleSpace()
{
	cout << "-------- TriangleSpace --------" << endl;
	for(int i=0; i<triangles.size(); i++)	
		triangles[i]->printContents();		
	cout << "------ TriangleSpace Ends ------" << endl;
	cout << "-------- Angle Space --------" << endl;
	for(int i=0; i<vertices.size(); i++)	
		vertices[i]->printAllContents();		
	cout << "------ Angle Space Ends ------" << endl;
	cout << "-------- Edge Space --------" << endl;
	for(int i=0; i<edges.size(); i++)	
		edges[i]->print();		
	cout << "------ Edge Space Ends ------" << endl;
}

map<int,EdgeBase*> AngleSpace::getEdgeMap()
{
	return edges;
}

map<int,VertexBase*> AngleSpace::getVertexMap()
{
	return vertices;
}

	double h = 1;

void AngleSpace::calcGradObjective(vector<double> &grad)
{
	for(int i=0; i<grad.size(); i++)
	{
		TriangleBase* tri = triangles[i/3];
		double a = tri->getCorners()[i%3]->getAngle(tri);
		double o = tri->getCorners()[i%3]->getOptimumAngle(tri);
		double w =  tri->getCorners()[i%3]->getWeight(tri);

		//grad[i] = w*(2*a*h - 2*o*h + h*h)/h;
		grad[i] = w*2*(a + o - h/2);
	}
}

void AngleSpace::calcGradTriangle(vector<double> &grad)
{
	for(int i=0; i<grad.size(); i++)
		grad[i] = 1;	

}

void AngleSpace::calcGradPlanar(vector<double> &grad)
{
	for(int i=0; i<grad.size(); i++)
	{
		TriangleBase* tri = triangles[i/3];
		VertexBase* vert = tri->getCorners()[i%3];
		
		if(!vert->onBoundary())
		{
			double initialPlan = abs(vert->sumAngles() - 360);
			double prevAngle = vert->getAngle(tri);
			vert->setAngle(tri, prevAngle + h);
			double modifiedPlan = abs(vert->sumAngles() - 360);
			vert->setAngle(tri, prevAngle);
			grad[i] = (modifiedPlan - initialPlan) /  h;
			//cout << " " << grad[i] << endl;
		}
		else
			grad[i] = 0;		
	}
	
	
	//for(int i=0; i<grad.size(); i++)
	//{
	//	TriangleBase* tri = triangles[i/3];
	//	if( tri->getCorners()[i%3]->onBoundary() )
	//		grad[i] = 0;
	//	else
	//		grad[i] = 1;
	//}
}

void AngleSpace::calcGradReconstruction(vector<double> &grad)
{
	for(int i=0; i<grad.size(); i++)
	{
		TriangleBase* tri = triangles[i/3];
		VertexBase* vert = tri->getCorners()[i%3];
		if(!vert->onBoundary())
		{
			double initialRecon = vert->reconstructability();
			double prevAngle = vert->getAngle(tri);
			vert->setAngle(tri, prevAngle + h);
			double modifiedRecon = vert->reconstructability();
			vert->setAngle(tri, prevAngle);
			grad[i] = ( modifiedRecon - initialRecon ) / h;
		}
		else
			grad[i] = 0;
	}
}

map<int,TriangleBase*> AngleSpace::getTriangleMap()
{
	return triangles;
}